package com.birdcage.gamemanagers;

import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Vector2;

///Singleton
///This will detect all physics logic of the game.
public class PhysicsManager
{
    ///Singleton Implement
    static public PhysicsManager GetInstance()
    {
        if (m_instance == null)
        {
            m_instance = new PhysicsManager();
        }       
        return m_instance;
    }
    
    private PhysicsManager(){};
    private static PhysicsManager m_instance = null;
    
    ///Public Method
    public void Update()
    {        
        Object[] allElements =  m_allElement.toArray();
        for (int i = 0; i < allElements.length; ++i)
        {
            PhysicsElement elem = (PhysicsElement)allElements[i];
            for (int j = i + 1; j < allElements.length; ++j)
            {
                PhysicsElement nextElem = (PhysicsElement)allElements[j];
                if (IsCollideRect(elem, nextElem))
                {
                    elem.AddColliedElement(nextElem);
                    nextElem.AddColliedElement(elem);
                } 
            }
            //when this element finished testing with all other elements, we will resolve to see if we are enter , update or exit.
            try
            {
                elem.ResolveCollision();
            } catch (IllegalArgumentException e)
            {
                e.printStackTrace();
            } catch (IllegalAccessException e)
            {
                 e.printStackTrace();
            } catch (InvocationTargetException e)
            {
                  e.printStackTrace();
            }
        }           
    }
    
    public void AddElement(PhysicsElement elem)
    {
        if (!m_allElement.contains(elem))
        {
            m_allElement.add(elem);
        }
    }
    
    ///Private Method
    private boolean IsCollide(PhysicsElement element1, PhysicsElement element2)
    {
        float radiusSum = element1.GetRadius() + element2.GetRadius();
        Vector2 worldPos = new Vector2();
        worldPos.set(element1.GetWorldPos());
        worldPos.sub(element2.GetWorldPos());
        float realDistance = worldPos.len();
        
        return realDistance < radiusSum;        
    }
    
    private boolean IsCollideRect(PhysicsElement element1, PhysicsElement element2)
    {
        float x1 = element1.GetWorldPos().x;
        float y1 = element1.GetWorldPos().y;
        float x2 = element2.GetWorldPos().x;
        float y2 = element2.GetWorldPos().y;
        float radiusSum = element1.GetRadius() + element2.GetRadius();
        
        boolean bXAdjust = Math.abs(x1 + element1.GetRadius() - x2 - element2.GetRadius()) < radiusSum;
        return bXAdjust && (Math.abs(y1 + element1.GetRadius() - y2 - element2.GetRadius()) < radiusSum);        
    }
    
    HashSet<PhysicsElement> m_allElement = new HashSet<PhysicsElement>();    
}
